TerraformでControl Tower管理下のAWSアカウントを別のOUに移動する(AFTなし)

TerraformでControl Tower管理下のAWSアカウントを別のOUに移動する(AFTなし)

Clock Icon2024.07.05

Control Tower管理下のAWSアカウントを別OUに移動する手順は、Control Tower管理外の環境と異なります。

今回はControl Tower管理下の既存のAWSアカウントをTerraformを使って、別OUに移動します。

前提

通常AWSアカウントのOU移動は、AWS Organizationsから変更可能です。

しかし、Control Tower管理下のAWSアカウントを別のOUに移動するには、AWS Service Catalogのプロビジョニングされた製品の設定を更新する必要があります。

https://docs.aws.amazon.com/ja_jp/controltower/latest/userguide/updating-account-factory-accounts.html
https://dev.classmethod.jp/articles/move-aws-accounts-between-ou-on-the-control-tower/
https://dev.classmethod.jp/articles/account-can-move-ou-easily-on-control-tower/

今回は以下を想定しています。

  • AWSアカウントをTerraformで管理している(aws_organizations_account)
  • IAM Identity Centerはセルフマネージド(AWS Control Towerで管理しない)
  • AWS Control Towerを導入して、OU移動の方法を変更する必要がでてきた
  • 対象のAWSアカウントはControl Tower管理下のOUに移動及びControl Towerへの登録も完了している
  • 移動先のOUもControl Tower管理下のOU

Terraformでは以下の記述があるとします。

organizations_account.tf
resource "aws_organizations_account" "sandbox" {
  email     = "sandbox@example.com"
  name      = "Sandbox"
  parent_id = "ou-XXXXX"
}

やってみた

Control Tower管理下のAWSアカウントに対して、TerraformでOU移動をやってみます。

AWS Service Catalogプロビジョニングされた製品をTerraformにimportする

執筆時点(2024/7)でControl TowerのAPIでAWSアカウントのOUを変更するものは提供されていないため、AWS Service Catalogを操作します。

importするために、プロビジョニングされた製品のIDを確認します。現時点では、dataでIDを取得することができないため、コンソールから確認します。

「AWSマネジメントコンソール」 -> 「AWS Service Catalog」 -> 「プロビジョニング」 -> 「プロビジョニングされた製品」 の順に選択します。

ID列の値をコピーしておきます。

プロビジョニングされた製品___Service_Catalog___ap-northeast-1

対象アカウントのAWS Service Catlogプロビジョニングされた製品をimportします。

import.tf
import {
  to = aws_servicecatalog_provisioned_product.sandbox
  id = "pp-XXXXX" # 前の手順で取得したID
}

HCLを生成します。

terraform plan -generate-config-out=service_catlog.tf
service_catalog.tf
# __generated__ by Terraform
# Please review these resources and move them into your main configuration files.

# __generated__ by Terraform from "pp-XXXXX"
resource "aws_servicecatalog_provisioned_product" "sandbox" {
  accept_language            = null
  ignore_errors              = null
  name                       = "Enroll-Account-XXXXXX"
  notification_arns          = null
  path_id                    = "lpv3-XXXXX"
  path_name                  = null
  product_id                 = "prod-XXXXX"
  product_name               = null
  provisioning_artifact_id   = "pa-XXXXX"
  provisioning_artifact_name = null
  retain_physical_resources  = null
  tags                       = {}
  tags_all                   = {}
}

不要な引数を削除して、必要なパラメータを追加しました。

service_catalog.tf
resource "aws_servicecatalog_provisioned_product" "sandbox1" {
  name                     = "Enroll-Account-12345678901"
  path_id                  = "lpv3-xxxxxx"
  product_id               = "prod-xxxxxxx"
  provisioning_artifact_id = "pa-xxxxxxx"

  provisioning_parameters {
    key   = "AccountName"
    value = "AWS Team Masaki Sato Sandbox 1"
  }
  provisioning_parameters {
    key   = "AccountEmail"
    value = "sandbox@example.com"
  }
  provisioning_parameters {
    key   = "ManagedOrganizationalUnit"
    value = "ControlTowerTest1 (ou-XXXXXX)"
  }
  provisioning_parameters {
    key   = "SSOUserFirstName"
    value = "NOT"
  }
  provisioning_parameters {
    key   = "SSOUserLastName"
    value = "USE"
  }
  provisioning_parameters {
    key   = "SSOUserEmail"
    value = "sandbox@example.com"
  }
}

provisioning_parametersで必要なパラメータは、Service Catalog -> 製品リスト -> 製品バージョンから確認できます。

Cursor_と_バージョンの詳細___Service_Catalog___ap-northeast-1

AccountNameAccountEmailに使う値は、AWS Control Towerのコンソール上から確認できる情報で問題ありません。

アカウント__AWS_Team_Masaki_Sato_Sandbox_1___ControlTowerTest1___MembersControlTowerOU___組織___Control_Tower___ap-northeast-1

ManagedOrganizationalUnitはService CatalogのテンプレートのParameterでAlloedValuesで定義されているものを使ってください。(Organizations名 (OU ID)の形式です。)

IAM Identity Center関連の以下のパラメータは、AWS Control TowerでIAM Identity Centerを管理している場合に利用されます。

  • SSOUserFirstName
  • SSOUserLastName
  • SSOUserEmail

セルフマネージドの場合は、適当な値で問題ありません。値が無いと製品更新時にエラーになってしまうので、適当な値を入れています。

準備ができたらApplyします。

terraform plan
terraform apply

aws_organizations_accountのOUの引数をignore_changeに設定

前の手順でaws_servicecatalog_provisioned_productでアカウントの所属先OUを管理しました。

aws_organizations_accountでも所属先OUを指定しており、2重管理になっています。

aws_organizations_account側で所属先OUを変更しないように、ignore_changesの記述を追加します。

organizations_account.tf
resource "aws_organizations_account" "sandbox" {
  email     = "sandbox@example.com"
  name      = "Sandbox"
-  parent_id = "ou-XXXXX"
+  lifecycle {
+    ignore_changes = [
+      parent_id
+    ]
+  }  
}

変更による差分がでないことを確認します。

terraform plan
# 実行結果抜粋
No changes. Your infrastructure matches the configuration.

AWSアカウントの所属OUを変更する

最後に動作確認で、AWSアカウントの所属OUを変更してみます。

OUControlTowerTest1にあるAWSアカウントAWS Team Masaki Sato Sandbox 1をOUControlTowerTest2に移動します。

Cursor_と_組織___Control_Tower___ap-northeast-1

provisioning_parametersのkeyManagedOrganizationalUnitを変更します。

service_catalog.tf
resource "aws_servicecatalog_provisioned_product" "sandbox1" {
  name                     = "Enroll-Account-12345678901"
  path_id                  = "lpv3-xxxxxx"
  product_id               = "prod-xxxxxxx"
  provisioning_artifact_id = "pa-xxxxxxx"

  provisioning_parameters {
    key   = "AccountName"
    value = "AWS Team Masaki Sato Sandbox 1"
  }
  provisioning_parameters {
    key   = "AccountEmail"
    value = "sandbox@example.com"
  }
  provisioning_parameters {
    key   = "ManagedOrganizationalUnit"
+    value = "ControlTowerTest2 (ou-YYYYYY)"
-    value = "ControlTowerTest1 (ou-XXXXXX)"
  }
  provisioning_parameters {
    key   = "SSOUserFirstName"
    value = "NOT"
  }
  provisioning_parameters {
    key   = "SSOUserLastName"
    value = "USE"
  }
  provisioning_parameters {
    key   = "SSOUserEmail"
    value = "sandbox@example.com"
  }
}

planを実行すると、パラメータが変更されることを確認できます。

terraform plan
# 抜粋
      ~ provisioning_parameters {
          ~ value              = "ControlTowerTest1 (ou-XXXXXX)" -> "ControlTowerTest2 (ou-YYYYYYY)"
            # (2 unchanged attributes hidden)
        }

applyを実行して、変更を適用します。Service Catalogの更新に時間がかかるため、10分程度かかります。

terraform apply

マネジメントコンソールから、所属OUを変更できていることが確認できました。

Baseline stateも登録済みになっているため、問題なさそうです。

組織___Control_Tower___ap-northeast-1

おわりに

Control Tower管理下のAWSアカウントのOU移動をTerraformを使ってやってみました。

執筆時点(2024/7)は、Control Tower管理下のAWSアカウントのOU移動を直接行うAPIやAWS Providerの機能はありません。

そのため、Service Catalogを更新する方法となりました。

以下のIssueにある通り、Landing ZoneのAPI等は少し前に提供されていたので、今後追加される可能性はあると思います。追加されたら、直感的に定義できるようになるので楽しみですね。

https://github.com/hashicorp/terraform-provider-aws/issues/21674

ちなみにAFTだと以下のように、OUとアカウントを定義できます。AWS Control Tower + Terraformを利用している方は検討してみてください。

https://dev.classmethod.jp/articles/slides-for-event-about-multi-accounts-management-by-aft/

以上、AWS事業本部の佐藤(@chari7311)でした。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.